/**
 * 
 */
package com.dalonedrau.jogl.engine;

import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;

import com.dalonedrau.jogl.util.UtilityMethods;
import com.jogamp.opengl.util.awt.TextRenderer;
import com.jogamp.opengl.util.texture.Texture;

/**
 * @author Donald
 */
@SuppressWarnings("unused")
public final class GameCanvasListener
		implements GLEventListener, KeyListener, MouseListener {
	/**
	 * the one and only instance of the <code>COBCanvasListener</code> class.
	 */
	private static GameCanvasListener	instance;
	static int							loops	= 0;
	static float						ra		= 0f;
	static long							store	= 0L;
	/** <code>LogItem</code> object. */
	// private static final Log logger =
	// LogFactory.getLog(COBCanvasListener.class);
	/**
	 * Gives access to the singleton instance of GameState.
	 * @return {@link GameState}
	 */
	public static GameCanvasListener getInstance() {
		return GameCanvasListener.instance;
	}
	/** the {@link GLDrawable} associated with this {@link GLEventListener}. */
	private GameCanvas		canvas;
	private boolean			clockingOutputEnabled	= true;
	/** the {@link GL} instance. */
	private GL				gl;
	/** the current gl location. */
	private Point			glLoc;
	/** the {@link GLU} instance. */
	private GLU				glu;
	private TextRenderer	sansserifBold36;
	/** the array of vertex buffer objects. */
	private int[]			vbos;
	/**
	 * Creates a new instance of COBCanvasListener.java.
	 * @param drawable the {@link COBCanvas} drawable
	 */
	public GameCanvasListener(final GameCanvas drawable) {
		super();
		canvas = drawable;
		GameCanvasListener.instance = this;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void display(final GLAutoDrawable drawable) {
		long now = System.nanoTime();
		try {
			// includes all operations to render (or re-render) the scene
			if (gl == null) {
				gl = drawable.getGL();
				gl.setSwapInterval(1);
			}
			gl.glClear(GL.GL_COLOR_BUFFER_BIT);

			// reset the color
			// gl.getGL2().glColor3f(1f, 1f, 1f);

			// prepare the view for rendering
			Interface.getInstance().prepareForRendering();
			long n1 = System.nanoTime();

			Render.getInstance().render(gl.getGL2());
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		GameCanvasListener.loops++;
		long diff = System.nanoTime() - now;
		GameCanvasListener.ra = (GameCanvasListener.store + diff)
				/ GameCanvasListener.loops;
		GameCanvasListener.store += diff;
		if (clockingOutputEnabled
				&& diff > 1000000) {
			System.out.println("starting display");
			System.out.println("display() -> took " + diff + "ns");
			System.out.println("ra: " + GameCanvasListener.ra + "ns");
			System.out.println("ra: "
					+ UtilityMethods.getInstance()
							.convertNanoToMilli((long) GameCanvasListener.ra)
					+ "ms");
		}
	}
	/**
	 * {@inheritDoc}
	 */
	public void displayChanged(final GLAutoDrawable drawable,
			final boolean modeChanged, final boolean deviceChanged) {
		// throw new UnsupportedOperationException("Not supported yet.");
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void dispose(final GLAutoDrawable drawable) {
		// TODO Auto-generated method stub

	}
	public int getTextureObject(final Texture texture) {
		return texture.getTextureObject(gl);
	}
	/**
	 * Gets the id of the vertex buffer object.
	 * @return int
	 */
	public int getVBO() {
		return vbos[0];
	}
	/** flag indicating whether vertex buffer objects are supported. */
	private boolean vboSupported = false;
	/**
	 * Gets flag indicating whether vertex buffer objects are supported
	 * @return true if the system's openGL support vertex buffer objects; 
	 * false otherwise
	 */
	public boolean isVboSupported() {
		return vboSupported;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init(final GLAutoDrawable drawable) {
		if (gl == null) {
			gl = drawable.getGL();
		}
		gl.setSwapInterval(1);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.getGL2().glShadeModel(GLLightingFunc.GL_SMOOTH);
		gl.glEnable(GL.GL_BLEND);
		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
		if (gl.getGL2().isFunctionAvailable("glGenBuffers")
				&& gl.getGL2().isFunctionAvailable("glBindBuffer")
				&& gl.getGL2().isFunctionAvailable("glBufferData")
				&& gl.getGL2().isFunctionAvailable("glDeleteBuffers")) {
			vboSupported = true;

			// create a VBO. each VBO has a unique id,
			// which is stored in an array
			vbos = new int[1];
			gl.getGL2().glGenBuffers(
					1, // the number of buffers
					vbos, // the array to store buffer ids
					0 // the offset. we'll use 0 exclusively
					);
		}
		GameController.getInstance().initTextureLibrary();

		GameController.getInstance().initAnimations();
		
		GameController.getInstance().initGameData();

		// setView(new IntroView());
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void keyPressed(final KeyEvent e) {
		Interface.getInstance().handleKeyEvent(e);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void keyReleased(final KeyEvent e) {}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void keyTyped(final KeyEvent e) {}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void mouseClicked(final MouseEvent e) {
		// TODO Auto-generated method stub
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void mouseEntered(final MouseEvent e) {
		// TODO Auto-generated method stub

	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void mouseExited(final MouseEvent e) {
		// TODO Auto-generated method stub

	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void mousePressed(final MouseEvent e) {
		Interface.getInstance().handleMousePress(e);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void mouseReleased(final MouseEvent e) {
		// TODO Auto-generated method stub

	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void reshape(final GLAutoDrawable drawable,
			final int x, final int y, final int width, final int height) {
		// reshape defines the rectangular region that will be
		// the new rendering canvas and defines the coordinate
		// system into which objects will be drawn
		if (gl == null) {
			gl = drawable.getGL();
		}
		if (glu == null) {
			glu = new GLU();
		}
		gl.glViewport(0, 0, width, height);
		gl.getGL2().glMatrixMode(GLMatrixFunc.GL_PROJECTION);
		gl.getGL2().glLoadIdentity();
		glLoc = new Point(0, 0);

		if (width <= height) {
			gl.getGL2().glOrtho(
					0, // left
					width, // right
					0, // bottom
					height, // top
					-1.0, // near
					1.0); // far
		} else {
			gl.getGL2().glOrtho(
					0, // left
					width, // right
					0, // bottom
					height, // top
					-1.0, // near
					1.0); // far
		}

		gl.getGL2().glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
		gl.getGL2().glLoadIdentity();
	}
}
